/* ================================================================================
//	Crypteviant!
//	Providing tough encrypted P2P Chat
//	Copyright (C) 2010  Martin Pfeifer, Tobias Rausch
//
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
// ============================================================================== */

#ifndef ENTROPYPOOL_HPP
#define ENTROPYPOOL_HPP

#include <QObject>
#include <QtCore/QMutex>
#include <QtCore/QMutexLocker>

#include "entropypooldata.hpp"


namespace RandomPool {

    /**
     * @var MINPOOLSIZE
     * @brief The minimum data which has to been added to the Pool until it can be used
    */
    static const int MINPOOLSIZE = 500; /** @todo How much random data is needed? */

    /**
     * @var MAXCACHETIME
     * @brief How often should the cache be skipped when the size is not optimal before it is forced to be added
    */
    static const int MAXCACHETIME = 10; /** @todo How long to wait until force adding cache */

    /**
     * @brief Pool which collects random data
     * @details The data will be added to a local cache until an optimal block size has been reached.\n
     * Then it will be added to the \ref EntropyPoolData which hashes it on-the-fly.\n
     * The Pools can be uniquely identified by its \b id property.
     *
     * @class EntropyPool entropypool.hpp "entropypool.hpp"
    */
    class EntropyPool : public QObject
    {
        Q_OBJECT

    public:
        /**
         * @brief Default Constructor
         *
         * @fn EntropyPool(QObject*)
         * @param parent
        */
        explicit EntropyPool(QObject *parent = 0);

        /**
         * @brief Add new random data to the internal data storage
         * @details The data is not added directly, it will first stored in a cache to optimize performance.
         *
         * @fn addData(const QString)
         * @param data
        */
        void addData(const QString data);

        /**
         * @brief Get the hashed data
         * @details A call to this function will check whether there is enough data in the hash.\n
         * Otherwise the cache will always be added to the hash (it may be that the size is not optimal).\n
         * This will be done as long as there is not enough data in the hash.\n
         * The call is \b blocking!\n
         * If you want to avoid a blocking call you need to check @ref EntropyPool::dataAvailable() const first.
         *
         * @fn getData()
         * @return QString
        */
        QString getData();

        /**
         * @brief This will check if there is enough data available to fetch
         * @details It may be possible that this function returns true but before you get the data using
         * @ref EntropyPool::getData() it has already been fetched by another Thread..
         *
         * @fn dataAvailable()
         * @return bool
        */
        bool dataAvailable();

    private:
        /**
         * @brief The block size which is optimal to add to the hash
         *
         * @fn checkOptimalBlockSize()
         * @return bool
        */
        bool checkOptimalBlockSize();


        /**
         * @var m_cache
         * @brief Stores newly added data to provide optimal performance
        */
        QString m_cache;

        /**
         * @var m_data
         * @brief Internal data storage
        */
        EntropyPoolData m_data;

        /**
         * @var m_optimalBlockSize
         * @brief The optimal size for new data which is added to the internal storage
        */
        unsigned int m_optimalBlockSize;

        /**
         * @var m_mutex
         * @brief Ensuring this class to be thread-safe
        */
        QMutex m_mutex;
    };

} // End of Namespace RandomPool

#endif // ENTROPYPOOL_HPP
